#ifndef PROCESS_POLL
#define PROCESS_POLL 1

#include "../http/httpconn.h"
#include "../epoller/epoller.h"
#include "../timer/heaptimer.h"
#include "../Logg/log.h"

#include <iostream>
#include <assert.h>
#include <memory>
#include <functional>
#include <unordered_map>


#include <sys/signal.h>
#include <sys/wait.h>
#include <mutex>
#include <sys/errno.h>
/*
    主进程控制 进程池 中的每个进程，每个进程可以（因为在每个进程当中使用epoll变相等于单进程多并发）负责多个客户端的通信
    信号处理/传递机制：父进程通过pipe与子进程进行管道信号通信,为什么？ 因为在多进程场景中,一定会存在信号机制，不管是主动/被动发出的信号，都应进行处理，多进程模式下的
    进程上下文都是相同的，不同子进程的异常退出都应将其进行正常的处理再退出,因此使用sigaction 使用更佳的信号处理机制再加上信号管道，精准控制每一个进程,
    使用socketpair();
    通信处理：使用socketpair
    子进程依然使用 epoll_ET模式与客户端进行通信,形成多进程模式下的多路IO复用 即多进程下的高并发

*/
/*
    使用 进程池 池化http连接 则大概模型为半异步模式,主进程只负责监听sock，子进程负责accept和解析连接
    中断信号函数触发时，在函数内对管道的另一端进行读写 形成一个原地受理并回射 进行自定义行为的二次触发
*/
class process  //每一个进程/线程都应该具有的基本属性 self_id + 与进程通信的 pipe[2]    使用socketpair() 建立全双工的通道
{
public:
    int self_id;
    int pipe[2];

public:
    process():self_id(-1),pipe{0,0}    {   }

};

static int SetNonblockFd(int fd);
static void sig_handler(int sig); 
static void add_sig(int sig,void(handler)(int) ,bool restart = true);

class process_poll
{
private:            //鸡毛单例模式？纯纯的私有函数在共有函数中被调用
    process_poll(int port,int processMax,int timeoutMS,
                int trigMode,bool Optlinger,bool Openlog,int loglevel,int logcapacity);
    process_poll(const process_poll &temp) = delete;                //禁用拷贝构造A(B)
    process_poll& operator=(const process_poll &temp) = delete;     //禁用赋值拷贝构造B=A;

public:
    static std::shared_ptr<process_poll> create(int port,int processMax,int timeoutMS,
                            int trigMode,bool Optlinger,bool Openlog,int loglevel,int logcapacity)
    {
        if(_ppoll_instance == nullptr)
        {
            _ppoll_instance.reset(new process_poll(port,processMax,timeoutMS,
                                                    trigMode,Optlinger,Openlog,loglevel,logcapacity));
            //std::cout<<"指针已经初始化"<<std::endl;
        }
        return _ppoll_instance;
    }
    ~process_poll()
    {
        close(ListenFd_);
        //free(srcDir_);
        //delete [] _proc_atribute;
    }

public:
    //启动进程池
    void run();

private:
    void setup_sig_pipe();
    void run_child();
    void run_parent();
    
    bool InitSock();
    void InitEventMode(int Mode);
    void AddClient(int fd,sockaddr_in addr);

    void SendError(int fd,const char *info);
    void ExtenTime(Httpconn* Client);
    void CloseCoon(Httpconn* Client);

    void DealAccept();
    void DealWrite(Httpconn* Client);
    void DealRead(Httpconn* Client);

    void Onread(Httpconn* Client);
    void OnWrite(Httpconn* Client);
    void OnProcess(Httpconn* Client);

private: //说人话---->线程池的参数设置
    //进程池中的最大 进程数
    static const int __POLL_MAX_VOLUME = 16;
    //每一个进程中可以处理的最大 epoll 请求 epoll_wait(handel,event,maxevent,timeout);
    static const int __EPOLL_MAX_EVENTS = 20480;
    //每一个进程可以处理的最大 客户请求
    static const int __PER_PROCESS_USERS = 40960;
    static const int MAX_FD=65536;


    unsigned short port_;
    //当前进程池中的总进程数
    int _NOW_PROCES_NUMBER;
    //随机访问的某个进程在进程池中的编号
    int _proc_index;
    int timeoutMS_;
    //进程的运行状态
    bool _proc_status;        //可以改成 union 针对一个进程,任何时刻都只有两种概念： 运行 / 停止
    //有关进程信息
    process *_proc_atribute;

    //进程中的 epoll 句柄
    //int _proc_epollhandel;


    //主进程的监听sock
    int ListenFd_;

    bool OptLinger_;

    //char *srcDir_;
    char *srcDir_;

    uint32_t listen_event;      //监听事件
    uint32_t coonfd_event;      //连接事件
    uint32_t pipe_event;        //管道屬性 

    std::unique_ptr<HeapTime> Timer_;
    std::unique_ptr<Epoller> epoller_;
    std::unordered_map<int,Httpconn> user_;
    
    //进程池的静态实例  //给所有的进程调取自身的编号等信息
    static std::shared_ptr<process_poll> _ppoll_instance;


};
#endif